package org.javaee05.component;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;

import java.sql.*;

/*封装Jdbc操作数据库CRUD的模板类(工具类)*/
public class jdbcTemplate {
    /*构造方法私有化*/
    private jdbcTemplate() {
    }

    /**
     * 调用此方法,执行一条插入语句,返回自增长的id
     *
     * @params sql 被执行的SQL语句
     * @params params 在sql语句中？占位符对应的参数，参数是可变长度的数组类型
     * 返回自增长的id,如果返回-1,说明插入失败
     */
    public static long insertAndReturnId(String sql, Object... params) {
        Connection connection = null;
        PreparedStatement pstmt = null;
        long id = -1;
        try {
            /*向连接池要一个连接对象*/
            connection = jdbcConnectionPool.getConnection();
            /*调用自己内部私有方法preparedSql预编译sql语句*/
            pstmt = connection.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS);
            /*执行sql语句*/
            if (null != params && params.length > 0) {
                /*params不为null,且长度大于1说明外部有参数传了过来,迭代params*/
                for (int i = 0; i < params.length; i++) {
                    /*i是从0开始的,但是?占位符从1开始,所以i+1*/
                    pstmt.setObject(i + 1, params[i]);
                }
            }
            pstmt.executeUpdate();
            /*获取存储自增长id的结果集对象*/
            ResultSet resultSet = pstmt.getGeneratedKeys();
            /*如果结果集有下一行数据*/
            if (resultSet.next())
            {
                /*取出第一列,赋值给id变量*/
                id = resultSet.getInt(1);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }finally
        {
            jdbcConnectionPool.closeConnection();//不要忘记在finally块中关闭数据连接
        }
        return id; //返回从结果集中取出的自增长id
    }

    /**
     *调用此方法,执行一条insert或update或delete的语句,返回自增长的id
     * dml语句都是改变的语句,所以这里起名update操作这三种受影响改变的方法
     * @params sql 被执行的SQL语句
     * @params params 在sql语句中？占位符对应的参数，参数是可变长度的数组类型
     *返回受影响的行数
     */
    public static int update(String sql,Object...params)
    {
        Connection connection = null;
        PreparedStatement pstmt = null;
        int row = -1;
        try {
            connection = jdbcConnectionPool.getConnection();
            pstmt = preparedSql(connection, sql, params);
            row = pstmt.executeUpdate();
        }catch (SQLException e)
        {
            e.printStackTrace();
        }
        finally {
            jdbcConnectionPool.closeConnection(); // 不要忘记在finally块中关闭数据库连接
        }
        return row;
    }

    /**
     * 调用此方法,执行一条插dql语句(select),返回自增长的id
     * @params sql 被执行的SQL语句
     * @params params 在sql语句中？占位符对应的参数，参数是可变长度的数组类型
     *  返回自增长的id
     *  返回查询列的结果集
     */
    public static ResultSet query(String sql,Object...params)
    {
        Connection connection = null;
        PreparedStatement pstmt = null;
        ResultSet resultSet = null;
        try {
            connection = jdbcConnectionPool.getConnection();
            pstmt = preparedSql(connection, sql, params);
            resultSet = pstmt.executeQuery();
        }catch (SQLException e)
        {
            e.printStackTrace();
        }
        finally {
            jdbcConnectionPool.closeConnection(); // 不要忘记在finally块中关闭数据库连接
        }
        return resultSet;
    }

    /**
     * 调用此方法, 执行一条DQL语句(select),返回将查询的结果集转换得到的json格式字符串
     * @param sql    被执行的SQL语句
     * @param params 该SQL语句中?占位符对应的参数,参数是可变长度的数组类型
     * @return       结果集转换得到的json字符串
     */
    public static  String queryAndReturnJson(String sql,Object...params)
    {
        return resultSetToJson(query(sql, params));
    }

    /**
     * 因为预编译sql的操作在本类中所有方法都需要做,因此抽取出公共方法,
     * 该方法只提供给本类其他方法使用,故定义为private
     * 因本类其他方法都是静态方法,因此这个公共的静态方法也需要设置为静态方法
     * 异常抛出给其他调用这个方法的方法处理
     */
    private static PreparedStatement preparedSql(Connection connection, String sql, Object... params)
            throws SQLException {
        PreparedStatement pstmt = connection.prepareStatement(sql);
        if (null != params && params.length > 0) {
            /*params不为null,且长度大于1说明外部有参数传了过来,迭代params*/
            for (int i = 0; i < params.length; i++) {
                /*i是从0开始的,但是?占位符从1开始,所以i+1*/
                pstmt.setObject(i + 1, params[i]);
            }
        }
        return pstmt;
    }
    /**
     * 将结果集ResultSetToJson转为json
     * @param resultSet 需要转为json的结果集
     * @return          json字符串
     */
    public static String resultSetToJson(ResultSet resultSet){
        JSONArray array = new JSONArray();
        try {
            ResultSetMetaData metaData = resultSet.getMetaData();
            int columnCount = metaData.getColumnCount();
            while (resultSet.next()) {
                JSONObject jsonObj = new JSONObject();
                for (int i = 1; i <= columnCount; i++) {
                    String columnName =metaData.getColumnLabel(i);
                    String value = resultSet.getString(columnName);
                    jsonObj.put(columnName, value);
                }
                array.add(jsonObj);
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return array.toString();
    }
}
